package com.lemon.exam.common.redis.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * Redis Hash 操作 类对象
 *
 * @author Lemon
 * @since 2025/7/4 18:02
 */
public final class HashOperations extends BaseOperations {
    public HashOperations(ObjectMapper objectMapper, ReactiveRedisTemplate<String, Object> template) {
        super(objectMapper, template);
    }

    /**
     * 添加
     *
     * @param key   键
     * @param field 字段
     * @param value 值
     * @return 是否成功
     */
    public <T> Mono<Boolean> put(String key, Object field, T value) {
        return withRetry(
                template.opsForHash().put(key, field, value),
                "redis hash put key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(false));
    }

    /**
     * 获取
     *
     * @param key   键
     * @param field 字段
     * @return 值
     */
    public Mono<Object> get(String key, Object field) {
        return withRetry(
                template.opsForHash().get(key, field),
                "redis hash get key: %s".formatted(key)
        ).onErrorResume(err -> Mono.empty());
    }

    /**
     * 获取
     *
     * @param key   键
     * @param field 字段
     * @param clazz 值类型
     * @return 值
     */
    public <T> Mono<T> get(String key, Object field, Class<T> clazz) {
        return withRetry(
                template.opsForHash().get(key, field).mapNotNull(toGeneric(clazz)),
                "redis hash get key: %s".formatted(key)
        ).onErrorResume(err -> Mono.empty());
    }

    /**
     * 获取
     *
     * @param key   键
     * @param clazz 值类型
     * @return 值
     */
    public <T> Flux<T> get(String key, Class<T> clazz) {
        return withRetry(
                template.opsForHash().entries(key).mapNotNull(toGeneric(clazz)),
                "redis hash get key: %s".formatted(key)
        ).onErrorResume(err -> Flux.empty());
    }

    /**
     * 删除
     *
     * @param key    键
     * @param fields 字段
     * @return 是否成功
     */
    public Mono<Boolean> del(String key, Object... fields) {
        return withRetry(
                template.opsForHash().remove(key, fields).map(v -> v != null && v == fields.length),
                "redis hash del key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(false));
    }

    /**
     * 获取大小
     *
     * @param key 键
     * @return 大小
     */
    public Mono<Long> size(String key) {
        return withRetry(
                template.opsForHash().size(key),
                "redis hash size key: %s".formatted(key)
        ).onErrorResume(err -> Mono.just(0L));
    }
}
